%module(directors="1") thostmduserapi

%{
#include <stdexcept>
#include <cstring>
%}

/* ========== SWIG 异常处理宏定义 ========== */
%define SWIG_exception(code, msg) do { throw std::runtime_error(msg); } while(0) %enddef

/* ========== 宏定义：将自定义指令映射到正确的 SWIG 指令 ========== */
%define %nodefaultcopy %nocopyctor %enddef

/* ========== 忽略所有类的赋值操作符 ========== */
%ignore *::operator=;

/* ========== Python 类型提示配置 ========== */
// 启用 Python 3 函数注解支持
%feature("python:annotations", "c");

// 为主要的 API 函数添加类型提示
%feature("autodoc", "1");

/* ========== 字符串数组类型映射 ========== */
// 为 char *[] 参数添加类型映射，支持 Python 字符串列表
%typemap(in) char *[] {
    if (!PyList_Check($input)) {
        PyErr_SetString(PyExc_TypeError, "Expected a list of strings");
        SWIG_fail;
    }
    
    int size = PyList_Size($input);
    $1 = (char **) malloc((size + 1) * sizeof(char *));
    
    for (int i = 0; i < size; i++) {
        PyObject *item = PyList_GetItem($input, i);
        if (!PyUnicode_Check(item)) {
            free($1);
            PyErr_SetString(PyExc_TypeError, "List items must be strings");
            SWIG_fail;
        }
        
        const char *str = PyUnicode_AsUTF8(item);
        if (!str) {
            free($1);
            SWIG_fail;
        }
        
        $1[i] = (char *) malloc((strlen(str) + 1) * sizeof(char));
        strcpy($1[i], str);
    }
    $1[size] = NULL;
}

/* ========== 3. 出参 char[] 高性能转码 ========== */
%typemap(out) char[ANY], char[] {
    if ($1 && $1[0]) {
        std::string u8 = gb2312_to_utf8($1);   // 线程局部，无拷贝
        resultobj = SWIG_FromCharPtrAndSize(u8.c_str(), u8.size());
    } else {
        resultobj = PyBytes_FromStringAndSize("", 0);   // 空串
    }
}

/* ========== 4. 入参 char** 和 char*[] 适配 Python3 list<str> ========== */
%typemap(in) char ** {
    if (!PyList_Check($input)) {
        PyErr_SetString(PyExc_TypeError, "Expected a list of strings");
        SWIG_fail;
    }
    
    int size = PyList_Size($input);
    $1 = (char **) malloc((size + 1) * sizeof(char *));
    
    for (int i = 0; i < size; i++) {
        PyObject *item = PyList_GetItem($input, i);
        if (!PyUnicode_Check(item)) {
            free($1);
            PyErr_SetString(PyExc_TypeError, "List items must be strings");
            SWIG_fail;
        }
        
        const char *str = PyUnicode_AsUTF8(item);
        if (!str) {
            free($1);
            SWIG_fail;
        }
        
        $1[i] = (char *) malloc((strlen(str) + 1) * sizeof(char));
        strcpy($1[i], str);
    }
    $1[size] = NULL;
}

%typemap(in) char *[] {
    if (!PyList_Check($input)) {
        PyErr_SetString(PyExc_TypeError, "Expected a list of strings");
        SWIG_fail;
    }
    
    int size = PyList_Size($input);
    $1 = (char **) malloc((size + 1) * sizeof(char *));
    
    for (int i = 0; i < size; i++) {
        PyObject *item = PyList_GetItem($input, i);
        if (!PyUnicode_Check(item)) {
            free($1);
            PyErr_SetString(PyExc_TypeError, "List items must be strings");
            SWIG_fail;
        }
        
        const char *str = PyUnicode_AsUTF8(item);
        if (!str) {
            free($1);
            SWIG_fail;
        }
        
        $1[i] = (char *) malloc((strlen(str) + 1) * sizeof(char));
        strcpy($1[i], str);
    }
    $1[size] = NULL;
}

%typemap(freearg) char ** {
    if ($1) {
        for (int i = 0; $1[i]; i++) {
            free($1[i]);
        }
        free($1);
    }
}

%typemap(freearg) char *[] {
    if ($1) {
        for (int i = 0; $1[i]; i++) {
            free($1[i]);
        }
        free($1);
    }
}


// 使用 %pythoncode 直接注入类型提示
%pythoncode %{
# 为 CThostFtdcMdApi 类添加类型提示
import typing
from typing import List

# 重新定义 CThostFtdcMdApi 的方法签名以包含类型提示
def _add_type_hints():
    # 获取原始的 CThostFtdcMdApi 类
    original_class = CThostFtdcMdApi
    
    # 保存原始方法
    original_subscribe = original_class.SubscribeMarketData
    original_unsubscribe = original_class.UnSubscribeMarketData
    original_subscribe_quote = original_class.SubscribeForQuoteRsp
    original_unsubscribe_quote = original_class.UnSubscribeForQuoteRsp
    original_register_spi = original_class.RegisterSpi
    original_register_front = original_class.RegisterFront
    original_register_nameserver = original_class.RegisterNameServer
    original_req_login = original_class.ReqUserLogin
    original_req_logout = original_class.ReqUserLogout
    
    # 创建带类型提示的包装方法
    def SubscribeMarketData(self, ppInstrumentID: 'List[str]', nCount: 'int') -> 'int':
        """订阅行情数据
        
        Args:
            ppInstrumentID: 合约代码列表
            nCount: 合约数量
            
        Returns:
            int: 操作结果
        """
        return original_subscribe(self, ppInstrumentID, nCount)
    
    def UnSubscribeMarketData(self, ppInstrumentID: 'List[str]', nCount: 'int') -> 'int':
        """退订行情数据
        
        Args:
            ppInstrumentID: 合约代码列表
            nCount: 合约数量
            
        Returns:
            int: 操作结果
        """
        return original_unsubscribe(self, ppInstrumentID, nCount)
    
    def SubscribeForQuoteRsp(self, ppInstrumentID: 'List[str]', nCount: 'int') -> 'int':
        """订阅询价响应
        
        Args:
            ppInstrumentID: 合约代码列表
            nCount: 合约数量
            
        Returns:
            int: 操作结果
        """
        return original_subscribe_quote(self, ppInstrumentID, nCount)
    
    def UnSubscribeForQuoteRsp(self, ppInstrumentID: 'List[str]', nCount: 'int') -> 'int':
        """退订询价响应
        
        Args:
            ppInstrumentID: 合约代码列表
            nCount: 合约数量
            
        Returns:
            int: 操作结果
        """
        return original_unsubscribe_quote(self, ppInstrumentID, nCount)
    
    def RegisterSpi(self, pSpi: 'CThostFtdcMdSpi') -> 'None':
        """注册回调接口
        
        Args:
            pSpi: 回调接口实例
        """
        return original_register_spi(self, pSpi)
    
    def RegisterFront(self, pszFrontAddress: 'str') -> 'None':
        """注册前置机网络地址
        
        Args:
            pszFrontAddress: 前置机网络地址
        """
        return original_register_front(self, pszFrontAddress)
    
    def RegisterNameServer(self, pszNameServer: 'str') -> 'None':
        """注册名字服务器网络地址
        
        Args:
            pszNameServer: 名字服务器网络地址
        """
        return original_register_nameserver(self, pszNameServer)
    
    def ReqUserLogin(self, pReqUserLoginField: 'CThostFtdcReqUserLoginField', nRequestID: 'int') -> 'int':
        """用户登录请求
        
        Args:
            pReqUserLoginField: 用户登录请求
            nRequestID: 请求编号
            
        Returns:
            int: 操作结果
        """
        return original_req_login(self, pReqUserLoginField, nRequestID)
    
    def ReqUserLogout(self, pUserLogout: 'CThostFtdcUserLogoutField', nRequestID: 'int') -> 'int':
        """登出请求
        
        Args:
            pUserLogout: 用户登出请求
            nRequestID: 请求编号
            
        Returns:
            int: 操作结果
        """
        return original_req_logout(self, pUserLogout, nRequestID)
    
    # 替换原始方法
    original_class.SubscribeMarketData = SubscribeMarketData
    original_class.UnSubscribeMarketData = UnSubscribeMarketData
    original_class.SubscribeForQuoteRsp = SubscribeForQuoteRsp
    original_class.UnSubscribeForQuoteRsp = UnSubscribeForQuoteRsp
    original_class.RegisterSpi = RegisterSpi
    original_class.RegisterFront = RegisterFront
    original_class.RegisterNameServer = RegisterNameServer
    original_class.ReqUserLogin = ReqUserLogin
    original_class.ReqUserLogout = ReqUserLogout
%}

%{
#include "ThostFtdcMdApi.h"
#include "./tools/iconv_wrapper.h"          // 高性能 GB→UTF8
#include <cstring>                              // 用于 memcpy

// 深拷贝函数：创建 CThostFtdcDepthMarketDataField 的完整副本
CThostFtdcDepthMarketDataField* CopyDepthMarketData(const CThostFtdcDepthMarketDataField* src) {
    if (!src) return nullptr;
    
    CThostFtdcDepthMarketDataField* dst = new CThostFtdcDepthMarketDataField();
    memcpy(dst, src, sizeof(CThostFtdcDepthMarketDataField));
    return dst;
}

// 释放深拷贝的数据
void FreeDepthMarketData(CThostFtdcDepthMarketDataField* data) {
    if (data) {
        delete data;
    }
}
%}

/* ========== 1. 给 director 补虚析构，消除 Warning 514 ========== */
%feature("director") CThostFtdcMdSpi;
%typemap(directorbase) CThostFtdcMdSpi %{
    virtual ~CThostFtdcMdSpi() {}
%}

/* ========== 2. 过滤行情用不到的常量 ========== */
%feature("director") CThostFtdcMdSpi;
%ignore THOST_FTDC_VTC_BankBankToFuture;
%ignore THOST_FTDC_VTC_BankFutureToBank;
%ignore THOST_FTDC_VTC_FutureBankToFuture;
%ignore THOST_FTDC_VTC_FutureFutureToBank;
%ignore THOST_FTDC_FTC_BankLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BrokerLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BankLaunchBrokerToBank;
%ignore THOST_FTDC_FTC_BrokerLaunchBrokerToBank;




%include "cpointer.i"

/* ========== 5. 禁用指针包装类的默认拷贝，保证仅以指针语义传递 ========== */
%nodefaultcopy CThostFtdcRspUserLoginFieldPtr;
%nodefaultcopy CThostFtdcRspInfoFieldPtr;
%nodefaultcopy CThostFtdcUserLogoutFieldPtr;
// 移除以下两行

%nodefaultcopy CThostFtdcSpecificInstrumentFieldPtr;
%nodefaultcopy CThostFtdcDepthMarketDataFieldPtr;
%nodefaultcopy CThostFtdcForQuoteRspFieldPtr;

/* ========== 6. MdSpi 回调结构体指针采用 %pointer_class，确保传递指针 ========== */
%pointer_class(CThostFtdcRspUserLoginField, CThostFtdcRspUserLoginFieldPtr);
%pointer_class(CThostFtdcRspInfoField, CThostFtdcRspInfoFieldPtr);
%pointer_class(CThostFtdcUserLogoutField, CThostFtdcUserLogoutFieldPtr);

%pointer_class(CThostFtdcSpecificInstrumentField, CThostFtdcSpecificInstrumentFieldPtr);
%pointer_class(CThostFtdcDepthMarketDataField, CThostFtdcDepthMarketDataFieldPtr);
%pointer_class(CThostFtdcForQuoteRspField, CThostFtdcForQuoteRspFieldPtr);

/* ========== 7. 包含头文件，定义类型和结构体 ========== */
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h"
%include "ThostFtdcMdApi.h"

/* ========== 8. 深拷贝函数声明，用于保存行情数据的完整副本 ========== */
// 创建 CThostFtdcDepthMarketDataField 的深拷贝
CThostFtdcDepthMarketDataField* CopyDepthMarketData(const CThostFtdcDepthMarketDataField* src);

// 释放深拷贝的数据
void FreeDepthMarketData(CThostFtdcDepthMarketDataField* data);

//%include "threads.i"  // 包含线程支持

/* ========== 9. 为 CThostFtdcDepthMarketDataField 添加 to_dict 方法 ========== */
%extend CThostFtdcDepthMarketDataField {
    PyObject* to_dict() {

        SWIG_PYTHON_THREAD_BEGIN_BLOCK;

        PyObject* dict = PyDict_New();
        if (!dict) 
        {
            SWIG_PYTHON_THREAD_END_BLOCK;
            return NULL;
        }
        
        PyObject* value = NULL;
        
        // Add string fields
        value = PyUnicode_FromString(self->TradingDay ? self->TradingDay : "");
        if (value) { PyDict_SetItemString(dict, "TradingDay", value); Py_DECREF(value); }
        
        value = PyUnicode_FromString(self->InstrumentID ? self->InstrumentID : "");
        if (value) { PyDict_SetItemString(dict, "InstrumentID", value); Py_DECREF(value); }
        
        value = PyUnicode_FromString(self->ExchangeID ? self->ExchangeID : "");
        if (value) { PyDict_SetItemString(dict, "ExchangeID", value); Py_DECREF(value); }
        
        value = PyUnicode_FromString(self->ExchangeInstID ? self->ExchangeInstID : "");
        if (value) { PyDict_SetItemString(dict, "ExchangeInstID", value); Py_DECREF(value); }
        
        value = PyUnicode_FromString(self->UpdateTime ? self->UpdateTime : "");
        if (value) { PyDict_SetItemString(dict, "UpdateTime", value); Py_DECREF(value); }
        
        value = PyUnicode_FromString(self->ActionDay ? self->ActionDay : "");
        if (value) { PyDict_SetItemString(dict, "ActionDay", value); Py_DECREF(value); }
        
        // Add price fields (double type)
        value = PyFloat_FromDouble(self->LastPrice);
        if (value) { PyDict_SetItemString(dict, "LastPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->PreSettlementPrice);
        if (value) { PyDict_SetItemString(dict, "PreSettlementPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->PreClosePrice);
        if (value) { PyDict_SetItemString(dict, "PreClosePrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->OpenPrice);
        if (value) { PyDict_SetItemString(dict, "OpenPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->HighestPrice);
        if (value) { PyDict_SetItemString(dict, "HighestPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->LowestPrice);
        if (value) { PyDict_SetItemString(dict, "LowestPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->ClosePrice);
        if (value) { PyDict_SetItemString(dict, "ClosePrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->SettlementPrice);
        if (value) { PyDict_SetItemString(dict, "SettlementPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->UpperLimitPrice);
        if (value) { PyDict_SetItemString(dict, "UpperLimitPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->LowerLimitPrice);
        if (value) { PyDict_SetItemString(dict, "LowerLimitPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->AveragePrice);
        if (value) { PyDict_SetItemString(dict, "AveragePrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->BandingUpperPrice);
        if (value) { PyDict_SetItemString(dict, "BandingUpperPrice", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->BandingLowerPrice);
        if (value) { PyDict_SetItemString(dict, "BandingLowerPrice", value); Py_DECREF(value); }
        
        // Add bid/ask prices
        value = PyFloat_FromDouble(self->BidPrice1);
        if (value) { PyDict_SetItemString(dict, "BidPrice1", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->AskPrice1);
        if (value) { PyDict_SetItemString(dict, "AskPrice1", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->BidPrice2);
        if (value) { PyDict_SetItemString(dict, "BidPrice2", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->AskPrice2);
        if (value) { PyDict_SetItemString(dict, "AskPrice2", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->BidPrice3);
        if (value) { PyDict_SetItemString(dict, "BidPrice3", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->AskPrice3);
        if (value) { PyDict_SetItemString(dict, "AskPrice3", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->BidPrice4);
        if (value) { PyDict_SetItemString(dict, "BidPrice4", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->AskPrice4);
        if (value) { PyDict_SetItemString(dict, "AskPrice4", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->BidPrice5);
        if (value) { PyDict_SetItemString(dict, "BidPrice5", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->AskPrice5);
        if (value) { PyDict_SetItemString(dict, "AskPrice5", value); Py_DECREF(value); }
        
        // Add volume and position fields (integer type)
        value = PyLong_FromLong(self->Volume);
        if (value) { PyDict_SetItemString(dict, "Volume", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->BidVolume1);
        if (value) { PyDict_SetItemString(dict, "BidVolume1", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->AskVolume1);
        if (value) { PyDict_SetItemString(dict, "AskVolume1", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->BidVolume2);
        if (value) { PyDict_SetItemString(dict, "BidVolume2", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->AskVolume2);
        if (value) { PyDict_SetItemString(dict, "AskVolume2", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->BidVolume3);
        if (value) { PyDict_SetItemString(dict, "BidVolume3", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->AskVolume3);
        if (value) { PyDict_SetItemString(dict, "AskVolume3", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->BidVolume4);
        if (value) { PyDict_SetItemString(dict, "BidVolume4", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->AskVolume4);
        if (value) { PyDict_SetItemString(dict, "AskVolume4", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->BidVolume5);
        if (value) { PyDict_SetItemString(dict, "BidVolume5", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->AskVolume5);
        if (value) { PyDict_SetItemString(dict, "AskVolume5", value); Py_DECREF(value); }
        
        value = PyLong_FromLong(self->UpdateMillisec);
        if (value) { PyDict_SetItemString(dict, "UpdateMillisec", value); Py_DECREF(value); }
        
        // Add large value fields (using double for handling)
        value = PyFloat_FromDouble(self->PreOpenInterest);
        if (value) { PyDict_SetItemString(dict, "PreOpenInterest", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->OpenInterest);
        if (value) { PyDict_SetItemString(dict, "OpenInterest", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->Turnover);
        if (value) { PyDict_SetItemString(dict, "Turnover", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->PreDelta);
        if (value) { PyDict_SetItemString(dict, "PreDelta", value); Py_DECREF(value); }
        
        value = PyFloat_FromDouble(self->CurrDelta);
        if (value) { PyDict_SetItemString(dict, "CurrDelta", value); Py_DECREF(value); }
    
        SWIG_PYTHON_THREAD_END_BLOCK;
        return dict;
    }
}